package com.polito.mad.bikeponyapp.persistence;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;

import com.polito.mad.bikeponyapp.persistence.DeliveryItem.DeliveryItemType;

public class DeliveryItemDAO extends  AbstractDAO<DeliveryItem,BikePonySQLiteHelper> {

	public static final int ID_COLUMN_INDEX = 0;
	public static final int DELIVERY_ID_COLUMN_INDEX = 1;
	public static final int ADDRESS_COLUMN_INDEX = 2;
	public static final int TYPE_COLUMN_INDEX = 3;
	public static final int ADDITIONAL_INFO_COLUMN_INDEX = 4;
	public static final int ESTIMATED_TIME_COLUMN_INDEX  = 5;
	public static final int LATITUDE_COLUMN_INDEX  = 6;
	public static final int LONGITUDE_COLUMN_INDEX  = 7;
	public static final int ORDER_COLUMN_INDEX  = 8;
	public static final int IMAGE_FILE_NAME_COLUMN_INDEX  = 9;
	private String[] cols; 
	
	public DeliveryItemDAO(Context ctx) {
		
		super(new BikePonySQLiteHelper(ctx, null,2));
		cols = new String[10];
		cols[ID_COLUMN_INDEX]="_id";
		cols[DELIVERY_ID_COLUMN_INDEX]="deliveryId";
		cols[TYPE_COLUMN_INDEX]="type";
		cols[ADDRESS_COLUMN_INDEX]="address";
		cols[ADDITIONAL_INFO_COLUMN_INDEX]="additionalInfo";
		cols[ESTIMATED_TIME_COLUMN_INDEX]="estimatedTime";
		cols[ORDER_COLUMN_INDEX]="_order";
		cols[LATITUDE_COLUMN_INDEX]="latitude";
		cols[LONGITUDE_COLUMN_INDEX]="longitude";
		cols[IMAGE_FILE_NAME_COLUMN_INDEX]="image_file_name";
		
	}

	@Override
	public DeliveryItem getCursor(Cursor c) {
		DeliveryItem item = new DeliveryItem();
		item.setId(c.getInt(ID_COLUMN_INDEX));
		item.setDeliveryId(c.getInt(DELIVERY_ID_COLUMN_INDEX));
		item.setDeliveryItemType(DeliveryItemType.fromType(c.getInt(TYPE_COLUMN_INDEX)));
		item.setAddress(c.getString(ADDRESS_COLUMN_INDEX));
		item.setAdditionalInfo(c.getString(ADDITIONAL_INFO_COLUMN_INDEX));
		item.setEstimatedTime(c.getLong(ESTIMATED_TIME_COLUMN_INDEX));
		item.setOrder(c.getInt(ORDER_COLUMN_INDEX));
		item.setLatitutde(c.getDouble(LATITUDE_COLUMN_INDEX));
		item.setLongitude(c.getDouble(LONGITUDE_COLUMN_INDEX));
		item.setImageFileName(c.getString(IMAGE_FILE_NAME_COLUMN_INDEX));
		return item;
	}

	@Override
	public DeliveryItem get(long id) {
		Cursor c = getDb().query(BikePonySQLiteHelper.DELIVERY_ITEM_DB_TABLE_NAME, cols, cols[ID_COLUMN_INDEX]+"=?", new String[]{String.valueOf(id)}, null, null, null);
		DeliveryItem item = null;
		if(c.moveToFirst())
		{
			item =  getCursor(c);
		}
		c.close();
		return item;
	}
	
	public List<DeliveryItem> findByDeliveryId(long deliveryId)
	{
		Cursor c = getDb().query(BikePonySQLiteHelper.DELIVERY_ITEM_DB_TABLE_NAME, cols, cols[DELIVERY_ID_COLUMN_INDEX]+"=?", new String[]{String.valueOf(deliveryId)}, null, null, cols[ORDER_COLUMN_INDEX]+" ASC");
		List<DeliveryItem> deliveryItems = new ArrayList<DeliveryItem>();
		if(c.moveToFirst())
		{
			while (!c.isAfterLast()) {
				deliveryItems.add(getCursor(c));
				c.moveToNext();
			}
		}
		c.close();
		return deliveryItems;
	}

	public List<DeliveryItem> addAll(List<DeliveryItem> deliveries) throws SQLException
	{
		//FIXME look at updateAll method and make them similar. Should I have to create a new list or it is necessary to rewrite old objects
		List<DeliveryItem> newItems = new ArrayList<DeliveryItem>();
		getDb().beginTransaction();
		try
		{
			for(DeliveryItem delivery : deliveries)
			{
				newItems.add(add(delivery));
			}
			getDb().setTransactionSuccessful();
			return newItems;			
		}finally
		{
			getDb().endTransaction();
			getDb().close();
		}
		
	}
	
	@Override
	public DeliveryItem add(DeliveryItem entity) throws SQLException 
	{
		ContentValues cValues = fillEntity(entity);
		DeliveryItem item= null;
		getDb().beginTransaction();
		try
		{
			long id = getDb().insert(BikePonySQLiteHelper.DELIVERY_ITEM_DB_TABLE_NAME, null, cValues);
			if(id==-1)
				throw new SQLException("an error occurred during DeliveryItem retrieval");
			item = get(id);
			getDb().setTransactionSuccessful();
		}finally
		{
			getDb().endTransaction();
		}
		return  item;
	}

	private ContentValues fillEntity(DeliveryItem entity) {
		ContentValues cValues = new ContentValues();
		cValues.put(cols[DELIVERY_ID_COLUMN_INDEX], entity.getDeliveryId());
		cValues.put(cols[TYPE_COLUMN_INDEX], entity.getDeliveryItemType().getType());
		cValues.put(cols[ADDRESS_COLUMN_INDEX], entity.getAddress());
		cValues.put(cols[ADDITIONAL_INFO_COLUMN_INDEX], entity.getAdditionalInfo());
		cValues.put(cols[ESTIMATED_TIME_COLUMN_INDEX], entity.getEstimatedTime());
		cValues.put(cols[ORDER_COLUMN_INDEX], entity.getOrder());
		cValues.put(cols[LONGITUDE_COLUMN_INDEX], entity.getLongitude());
		cValues.put(cols[LATITUDE_COLUMN_INDEX], entity.getLatitutde());
		cValues.put(cols[IMAGE_FILE_NAME_COLUMN_INDEX], entity.getImageFileName());
		return cValues;
	}

	@Override
	public void delete(DeliveryItem entity) throws SQLException {
		
		getDb().beginTransaction();
		try
		{
			int deletedRows = getDb().delete(BikePonySQLiteHelper.DELIVERY_ITEM_DB_TABLE_NAME, cols[ID_COLUMN_INDEX]+"=?", new String[]{String.valueOf(entity.getId())});
			
			if(deletedRows==0)
				throw new SQLException("deliveryItem not deleted");
			List<DeliveryItem> items = getAll();
			for(int i=0;i<items.size();i++)
			{
				DeliveryItem item = items.get(i);
				item.setOrder(i);
			}
			updateAll(items);
			getDb().setTransactionSuccessful();
		}finally
		{
			getDb().endTransaction();
		}
	}

	@Override
	protected String[] getColumnNames() {
		return cols;
	}

	@Override
	protected String getDbName() {
		return BikePonySQLiteHelper.BIKE_PONY_DB_NAME;
	}

	@Override
	public List<DeliveryItem> getAll() {
		List<DeliveryItem> l=new ArrayList<DeliveryItem>();
		Cursor c= getDb().query(BikePonySQLiteHelper.DELIVERY_ITEM_DB_TABLE_NAME,cols, null, null, null, null, cols[ORDER_COLUMN_INDEX]+" ASC");
		c.moveToFirst();
		while (!c.isAfterLast()) {
			l.add(getCursor(c));
			c.moveToNext();
		}
		c.close();
		return l;
	}
	
	public Cursor getAllAsCursor()
	{
		getDb().close();
		Cursor c= getDb().query(BikePonySQLiteHelper.DELIVERY_ITEM_DB_TABLE_NAME,cols, null, null, null, null, cols[ORDER_COLUMN_INDEX]+" ASC");
		return c;
	}
	
	public DeliveryItem update(DeliveryItem deliveryItem)throws SQLException
	{
		getDb().beginTransaction();
		int affectedRows = getDb().update(BikePonySQLiteHelper.DELIVERY_ITEM_DB_TABLE_NAME, fillEntity(deliveryItem), cols[ID_COLUMN_INDEX]+" = ?", new String[]{String.valueOf(deliveryItem.getId())});
		try
		{
			if(affectedRows!=1)
			{
				throw new SQLException("unable to update the database");
			}
			deliveryItem = get(deliveryItem.getId());
			getDb().setTransactionSuccessful();
			return deliveryItem;
		}finally
		{
			getDb().endTransaction();
		}
	}
	
	public List<DeliveryItem> updateAll(List<DeliveryItem> items)throws SQLException
	{
		getDb().beginTransaction();
		try
		{
			for(DeliveryItem item : items)
			{
				item = update(item);
			}
			getDb().setTransactionSuccessful();
			return items;
		}finally
		{
			getDb().endTransaction();
		}
	}

	
	
	@Override
	public List<DeliveryItem> findByQuery(String whereClause) {
		
		Cursor c = getDb().query(BikePonySQLiteHelper.DELIVERY_ITEM_DB_TABLE_NAME,null,whereClause,null,null,null,null);
		List<DeliveryItem> deliveryItems = new ArrayList<DeliveryItem>();
		if(c.moveToFirst())
		{
			while (!c.isAfterLast()) {
				deliveryItems.add(getCursor(c));
				c.moveToNext();
			}
		}
		c.close();
		return deliveryItems;
	}

	@Override
	public int count() {
		Cursor c = getDb().query(BikePonySQLiteHelper.DELIVERY_ITEM_DB_TABLE_NAME, new String[]{"MAX("+cols[ORDER_COLUMN_INDEX]+")"}, null, null, null, null, null);
		if(c.moveToFirst())
		{
			return c.getInt(0);
		}
		return -1;
	}

	@Override
	public String getColumnNameByIndex(int colIndex) {
		return cols[colIndex];
	}

	@Override
	public int deleteAll(List<DeliveryItem> items) throws SQLException {
		int countDeleted =0;
		if(items==null)
			return countDeleted;
		getDb().beginTransaction();
		try
		{
			for(DeliveryItem item : items)
			{
				delete(item);
				countDeleted++;
			}
			getDb().setTransactionSuccessful();
			return countDeleted;
		}finally
		{
			getDb().endTransaction();
		}
		
	}
}
